
#include "common.h"
void GetBundleCntPtPublications(CATIProduct *ipiCntProduct, CATBaseUnknown *iBundleCntPt /*check against*/,
                                CATListValCATBaseUnknown_var *&pListObject /*output*/)
{
    CATIPrdObjectPublisher *piPublisher = NULL;

    if (NULL != ipiCntProduct)
    {
        HRESULT rc = ipiCntProduct->QueryInterface(IID_CATIPrdObjectPublisher,
                                                   (void **)&piPublisher);
        if (SUCCEEDED(rc) && piPublisher)
        {
            //
            // List publications directly on the geometry
            //
            CATUnicodeString pBundleCntPtName = "";
            CATListValCATUnicodeString *pNameList = NULL;
            rc = piPublisher->IsPublished(iBundleCntPt, pNameList);
            if (rc && NULL != pNameList && pNameList->Size() > 0)
            {
                pBundleCntPtName = (*pNameList)[1];
            }
            //  Retrieve the list of the publications of the current product.
            //
            CATListValCATUnicodeString *pPubList = NULL;
            int pubCount = piPublisher->ListPublications(pPubList);
            if (pubCount > 0 && pPubList)
            {
                for (int i = 1; i <= pubCount; i++)
                {
                    CATUnicodeString pName = (*pPubList)[i];
                    if (pName.SearchSubString(pBundleCntPtName, 0, CATUnicodeString::CATSearchModeForward) > 0)
                    {
                        CATBaseUnknown *publisher = NULL;
                        publisher = piPublisher->GetFinalObject(pName);

                        if (publisher)
                        {
                            pListObject->Append((CATBaseUnknown_var)publisher);
                        }
                    }
                }
            }
        }
    }
}
CATISpecObject_var GetPartFeature(CATIProduct *piRootProduct)
{
    if (!piRootProduct)
        return NULL_var;
    CATIProduct_var spRef = piRootProduct->GetReferenceProduct();

    if (NULL_var != spRef)
    {
        CATILinkableObject *piLinkableObject = NULL;
        HRESULT rc = spRef->QueryInterface(IID_CATILinkableObject, (void **)&piLinkableObject);

        if (SUCCEEDED(rc))
        {
            // Do not release the document pointer
            CATDocument *pDocument = NULL;
            pDocument = piLinkableObject->GetDocument();
            CATIContainerOfDocument *pIContainerOfDocumentOnDoc = NULL;
            rc = pDocument->QueryInterface(IID_CATIContainerOfDocument,
                                           (void **)&pIContainerOfDocumentOnDoc);
            if (SUCCEEDED(rc))
            {
                CATIContainer *pIContainer = NULL;
                rc = pIContainerOfDocumentOnDoc->GetSpecContainer(pIContainer);
                if (SUCCEEDED(rc) && pIContainer)
                {
                    CATIPrtContainer *pPrtContainer = NULL;
                    rc = pIContainer->QueryInterface(IID_CATIPrtContainer, (void **)&pPrtContainer);
                    if (SUCCEEDED(rc))
                    {
                        CATISpecObject_var spSpecObjectOnPart = pPrtContainer->GetPart();
                        return spSpecObjectOnPart;
                    }
                }
            }
        }
    }
    return NULL_var;
}
HRESULT CopyWithLink(CATIProduct *piSourceInstance, CATIProduct *piTargetInstance,
                     CATISpecObject_var &spCopyObject, CATISpecObject_var &spPasteTarget, CATISpecObject_var &spPasteResult)
{
    // 复制
    HRESULT rc = E_FAIL;
    if (spCopyObject == NULL_var)
        return E_FAIL;

    CATISpecObject_var ObjectToCopy = spCopyObject;
    CATISpecObject_var PasteTarget = spPasteTarget;
    CATMmrInterPartCopy *CopyAndPaste = new CATMmrInterPartCopy(ObjectToCopy, PasteTarget);

    rc = CopyAndPaste->SetSourceInstance(piSourceInstance);
    if (FAILED(rc))
    {
        cout << "SetSourceInstance failed" << endl;
        return E_FAIL;
    }
    rc = CopyAndPaste->SetTargetInstance(piTargetInstance);
    if (FAILED(rc))
    {
        cout << "SetTargetInstance failed" << endl;
        return E_FAIL;
    }
    CATBoolean CoptWithLink = TRUE;
    rc = CopyAndPaste->SetLinkMode(CoptWithLink);
    if (FAILED(rc))
    {
        cout << "SetLinkMode failed" << endl;
        return E_FAIL;
    }
    CATUnicodeString *ErrorMessage = new CATUnicodeString("");
    rc = CopyAndPaste->Run(ErrorMessage);
    if (FAILED(rc))
    {
        cout << "Run failed" << endl;
        cout << *ErrorMessage << endl;
        return E_FAIL;
    }
    rc = CopyAndPaste->GetResult(spPasteResult); // 复制的对象
    if (FAILED(rc))
    {
        cout << "GetResult failed" << endl;
        return E_FAIL;
    }
    return S_OK;
}
HRESULT CopyWithLink(CATIProduct *piSourceInstance, CATIProduct *piTargetInstance,
                     CATIBRepAccess_var &spCopyObject, CATISpecObject_var &spPasteTarget, CATISpecObject_var &spPasteResult)
{
    // 复制
    HRESULT rc = E_FAIL;
    if (spCopyObject != NULL_var)
    {
        /*CATIAlias* piAlias = NULL;
        rc = spCopyObject->QueryInterface(IID_CATIAlias, (void**)&piAlias);
        cout<<"++++++++++++++++++++++++++++"<<endl;
        cout<<"The Copy Object Alias is "<<piAlias->GetAlias()<<endl;
        cout<<"++++++++++++++++++++++++++++"<<endl;*/
    }
    else
    {
        // cout<<"The Copy Object is NULL_var"<<endl;
        return E_FAIL;
    }

    CATIBRepAccess_var ObjectToCopy = spCopyObject;
    CATISpecObject_var PasteTarget = spPasteTarget;
    CATMmrInterPartCopy *CopyAndPaste = new CATMmrInterPartCopy(ObjectToCopy, PasteTarget);

    rc = CopyAndPaste->SetSourceInstance(piSourceInstance);
    if (FAILED(rc))
    {
        cout << "SetSourceInstance failed" << endl;
        return E_FAIL;
    }
    rc = CopyAndPaste->SetTargetInstance(piTargetInstance);
    if (FAILED(rc))
    {
        cout << "SetTargetInstance failed" << endl;
        return E_FAIL;
    }
    CATBoolean CoptWithLink = TRUE;
    rc = CopyAndPaste->SetLinkMode(CoptWithLink);
    if (FAILED(rc))
    {
        cout << "SetLinkMode failed" << endl;
        return E_FAIL;
    }
    CATUnicodeString *ErrorMessage = new CATUnicodeString("");
    rc = CopyAndPaste->Run(ErrorMessage);
    if (FAILED(rc))
    {
        cout << "Run failed" << endl;
        cout << *ErrorMessage << endl;
        return E_FAIL;
    }
    rc = CopyAndPaste->GetResult(spPasteResult); // 复制的对象
    if (FAILED(rc))
    {
        cout << "GetResult failed" << endl;
        return E_FAIL;
    }
    return S_OK;
}
HRESULT linkpoint(CATIEhiBnlSegmentExtremity *bundleExtremity, CATIProduct *piInstanceConnector, CATIEhiBundleSegment *bundleSegment, CATIEhiMultiBranchable *piMultiBranchable, bool is_append)
{
    CATIElbSingleConnector *pElecSingleConnector = NULL;
    if (FAILED(piInstanceConnector->QueryInterface(IID_CATIElbSingleConnector, (void **)&pElecSingleConnector)) && pElecSingleConnector)
    {
        return E_FAIL;
    }
    CATListValCATBaseUnknown_var *pListBundleCnctPtOfSic = NULL;
    if (FAILED(pElecSingleConnector->ListBundleCnctPts(pListBundleCnctPtOfSic)))
    {
        return E_FAIL;
    }
    int NumberOfBCP = pListBundleCnctPtOfSic ? pListBundleCnctPtOfSic->Size() : 0;
    if (NumberOfBCP < 1)
    {
        return E_FAIL;
    }
    CATISpecObject_var spSO = (*pListBundleCnctPtOfSic)[1]; // 默认取第1个BundleCnctPts
    if (spSO == NULL_var)
    {
        return E_FAIL;
    }
    CATIAlias *conAlias = NULL;
    if (FAILED(piInstanceConnector->QueryInterface(IID_CATIAlias, (void **)&conAlias)) || conAlias == NULL)
    {
        return E_FAIL;
    }
    cout << "> connector name: " << conAlias->GetAlias() << endl;
    CATBaseUnknown *pObject = NULL;
    CATListValCATBaseUnknown_var *pListObject = new CATLISTV(CATBaseUnknown_var);

    CATIElbBundleCnctPt *pBundleCntPt = NULL;
    if (spSO->QueryInterface(IID_CATIElbBundleCnctPt, (void **)&pBundleCntPt) || pBundleCntPt == NULL)
    {
        return E_FAIL;
    }
    pObject = pBundleCntPt;
    GetBundleCntPtPublications(piInstanceConnector, pObject, pListObject);
    if (pListObject->Size() == 0)
    {
        return E_FAIL;
    }

    CATIProduct *bundleSegmentProduct;
    if (FAILED(piMultiBranchable->QueryInterface(IID_CATIProduct, (void **)&bundleSegmentProduct)))
    {
        return E_FAIL;
    }
    CATISpecObject_var spPasteResult = NULL_var;
    CATISpecObject_var spPartF = GetPartFeature(bundleSegmentProduct);
    if (spPartF == NULL_var)
    {
        return E_FAIL;
    }
    int NumberOfObject = pListObject ? pListObject->Size() : 0;
    CATListValCATISpecObject_var *iSet = new CATLISTV(CATISpecObject_var);
    CATIConnector *pCnt;
    CATISpecObject_var spPObject;
    HRESULT rc;
    for (int indexOfObject = 1; indexOfObject <= NumberOfObject; indexOfObject++)
    {
        // 获取发布元素对应的几何元素
        pCnt = NULL;
        if (FAILED((*pListObject)[indexOfObject]->QueryInterface(IID_CATIConnector, (void **)&pCnt)) || pCnt == NULL)
        {
            return E_FAIL;
        }
        CATILinkableObject_var pPObject = NULL_var;
        pPObject = pCnt->GiveReferenceObject();
        if (pPObject == NULL_var)
        {
            return E_FAIL;
        }
        // 根据几何元素的不同类型,分情况复制
        spPObject = NULL_var;

        rc = pPObject->QueryInterface(IID_CATISpecObject, (void **)&spPObject);
        if (SUCCEEDED(rc) && spPObject != NULL_var)
        {
            // 复制 curve, line, surface, plane, point, sketch, solid feature
            rc = CopyWithLink(piInstanceConnector, bundleSegmentProduct, spPObject, spPartF, spPasteResult);
        }
        else
        {
            // 复制 rsur, redge, vertex
            CATIBRepAccess_var spBRepObject;
            rc = pPObject->QueryInterface(IID_CATIBRepAccess, (void **)&spBRepObject);
            if (SUCCEEDED(rc) && spBRepObject != NULL_var)
            {
                rc = CopyWithLink(piInstanceConnector, bundleSegmentProduct, spBRepObject, spPartF, spPasteResult);
            }
        }
        if (SUCCEEDED(rc) && spPasteResult != NULL_var)
            iSet->Append(spPasteResult);
    }
    if (iSet->Size() < 2)
    {
        return E_FAIL;
    }

    if (FAILED(SetBranchableRoute(bundleSegment, *iSet, is_append)))
    {
        return E_FAIL;
    }

    if (FAILED(bundleExtremity->Connect(pBundleCntPt)))
    {
        return E_FAIL;
    }

    return S_OK;
}
HRESULT SetBranchableRoute(CATIEhiBundleSegment *piBranchable, CATLISTV(CATISpecObject_var) & iSet, bool is_append)
{
    HRESULT rc = E_FAIL;
    //
    if (!piBranchable)
        return E_FAIL; // pointer not valuated : exit E_FAIL
    if (iSet.Size() < 1)
        return E_FAIL; // number of points < 2 : exit E_FAIL;

    // -- retrieving electrical curve
    CATIGSMSpline *pGSMSpline = NULL;

    rc = piBranchable->GetElecCurve(&pGSMSpline);
    if (FAILED(rc) || (NULL == pGSMSpline))
        return E_FAIL;

    // -- retrieving container
    CATIContainer_var spCont; // the container
    CATISpecObject_var spObj = pGSMSpline;
    if (NULL_var != spObj)
        spCont = spObj->GetFeatContainer();

    // -- retrieving factories :
    //             -   GSM factory
    CATIGSMFactory_var spGSMfacto = spCont; // GSM factory
    if (spGSMfacto == NULL_var)
        return E_FAIL;

    // remove the last point
    int pos = 1;
    if (is_append)
    {
        rc = pGSMSpline->GetSize(pos);
    }
    if (SUCCEEDED(rc) && pos > 0)
    {
        if (FAILED(pGSMSpline->RemovePointAtPosition(pos)))
        {
            return E_FAIL;
        }
    }
    // -- Query this interface on the geometrical feature to be checked.
    //       -  CATIMfZeroDimResult, The query will succeed if all the domains of the resulting body are zero dimensional.
    //        - CATIMfMonoDimResult, The query will succeed if all the domains of the resulting body are mono dimensional.
    //       -  CATIMfBiDimResult,  The query will succeed if all the domains of the resulting body are two dimensional.
    CATIMfZeroDimResult *constraintPoint = NULL;
    CATIMfMonoDimResult *constraintCurve = NULL;
    CATIMfBiDimResult *constraintPlane = NULL;

    // --- add constraint point and TangentDirection to electrical curve
    // --- (1) add constraint point
    for (int i = 1; i <= iSet.Size(); i++)
    {
        if (!constraintPoint)
        {
            if (SUCCEEDED(iSet[i]->QueryInterface(IID_CATIMfZeroDimResult, (void **)&constraintPoint)))
            {
                iSet[i]->Update();
                if (is_append)
                {
                    pGSMSpline->Add(iSet[i]);
                }
                else
                {
                    pGSMSpline->InsertBeforePosition(iSet[i], 1);
                }
            }
        }
    }

    // --- (2) add TangentDirection
    if (constraintPoint)
    {
        for (int i = 1; i <= iSet.Size(); i++)
        {
            if (!constraintPlane && !constraintCurve)
            {
                if (SUCCEEDED(iSet[i]->QueryInterface(IID_CATIMfBiDimResult, (void **)&constraintPlane)) ||
                    SUCCEEDED(iSet[i]->QueryInterface(IID_CATIMfMonoDimResult, (void **)&constraintCurve)))
                {
                    CATIGSMDirection_var spGSMDirec = NULL_var;
                    spGSMDirec = spGSMfacto->CreateDirection(iSet[i]);
                    if (spGSMDirec != NULL_var)
                    {
                        CATIGSMDirection *dir = spGSMDirec;
                        int type = dir->GetDirectionType();
                        double X;
                        double Y;
                        double Z;
                        double X1;
                        double Y1;
                        double Z1;
                        rc = dir->GetLocalCoordinates(X, Y, Z);
                        rc = dir->GetCoordinates(X1, Y1, Z1);

                        pos = 1;
                        if (is_append)
                        {
                            rc = pGSMSpline->GetSize(pos);
                        }
                        if (SUCCEEDED(rc) && pos > 0 && constraintPlane) // 如果是平面约束，设置切向方向
                        {
                            pGSMSpline->AddTangentDirection(spGSMDirec, pos);
                            if (is_append == false)
                            {
                                pGSMSpline->InvertDirection(pos);
                            }
                        }
                        if (constraintCurve) // 如果是曲线约束，设置曲线切向约束方向
                        {
                            pGSMSpline->SetCurveConstraint(iSet[i], pos);
                            pGSMSpline->SetCurveConstraintType(pGSMSpline->CATIGSMConstraintFromCurveType::Tangency, pos);
                        }
                    }
                }
            }
        }
    }

    if (constraintPlane)
    {
        constraintPlane->Release();
        constraintPlane = NULL;
    }

    if (constraintCurve)
    {
        constraintCurve->Release();
        constraintCurve = NULL;
    }

    if (constraintPoint)
    {
        constraintPoint->Release();
        constraintPoint = NULL;
    }
    // spObj->Update();
    pGSMSpline->Release();
    pGSMSpline = NULL;

    //
    rc = S_OK;
    //
    return rc;
}
HRESULT get_extremity_name(CATIEhiBnlSegmentExtremity *piBundleSegmentExtremity, std::string &ext_name)
{
    CATBaseUnknown *ExtremityPoint = NULL;
    HRESULT rc = piBundleSegmentExtremity->GetRepresentation(&ExtremityPoint);
    CATIAlias *ExtremityPointAlias = NULL;
    if (ExtremityPoint)
    {
        rc = ExtremityPoint->QueryInterface(IID_CATIAlias, (void **)&ExtremityPointAlias);
        if (SUCCEEDED(rc) && ExtremityPointAlias)
            ext_name = ExtremityPointAlias->GetAlias();
    }
    return rc;
}
HRESULT set_connector(std::map<std::string, CATIProduct *> &connectors_list, std::map<std::string, std::string> &point_to_connector_list, std::string ext_name, CATIProduct *&connector_inst)
{

    if (point_to_connector_list.count(ext_name) > 0)
    {
        std::string connector_name = point_to_connector_list[ext_name];
        connector_inst = connectors_list[connector_name];
        return S_OK;
    }

    return E_FAIL;
}